package samelevelregion


import java.sql.Connection
import java.sql.DriverManager
import java.sql.PreparedStatement
import java.sql.ResultSet
import java.util.concurrent.atomic.AtomicInteger

class CreateSameLevelRegion {

    static {
        Class.forName("oracle.jdbc.driver.OracleDriver")
    }

    //数据库地址
    static String url = "jdbc:oracle:thin:@10.16.23.26:1521:ufgovdb1"
    //用户名
    static String username = "PHDEVCRUX0210"
    //密码
    static String password = "crux"

    static Connection connection;

    static {
        connection = DriverManager.getConnection(url, username, password)
        connection.setAutoCommit(false)
    }


    public static void main(String[] args) {
        CreateSameLevelRegion createSameLevelRegion = new CreateSameLevelRegion();
        Region region = createSameLevelRegion.getRegionInstance();
        //查询的字段列表
        String propStr = getClassFieldList(region.getClass())
        //select * from org_region where inner_code like '0001000d%' and inner_code <>'0001000d' order by inner_code;
        //00010006 00010009 00010007
        PreparedStatement ps = connection.prepareStatement("select $propStr from org_region where inner_code like '000100030001%'  order by inner_code")
        ResultSet rs = ps.executeQuery();

        //需要插入本级的区划集合
        List<Region> regions = getObjList(rs, region.getClass())

        println(regions.size())
        println(regions)

        rs.close()
        ps.close()

        //再每个区划下插入本级区划
        regions.forEach({ currentRegion ->
            createRegion(currentRegion, regions)
        })

        connection.close()
    }


    //创建currentRegion的本级区划
    public static void createRegion(Region currentRegion, List<Region> regions) {
        //创建本级区划
        //如果当前区划是本级区划。跳过
        if(currentRegion.name.endsWith("本级")){
            return;
        }
        //确认还没有创建
        boolean hasCreate = false;
        for (Region region : regions) {
            if (region.name.equals(currentRegion.name + "本级") && (region.parent_id == currentRegion.id)) {
                hasCreate = true
                break;
            }
        }
        if (hasCreate) {
            return;
        }
        //查询所有下级
        List<Region> subRegions = []
        regions.forEach({ region ->
            if (region.parent_id == currentRegion.id) {
                subRegions.add(region)
            }
        })

        Region insertRegion = currentRegion.class.newInstance()

        insertRegion.id = GenId.generate()
        insertRegion.code = currentRegion.code;
        insertRegion.name = currentRegion.name + "本级"
        //insertRegion.inner_code = currentRegion.
        insertRegion.enabled = 1;
        insertRegion.leaf_node = 0;
        insertRegion.level_num = currentRegion.level_num + 1
        insertRegion.year = 2019
        insertRegion.parent_id = currentRegion.id
        insertRegion.is_top_level = 0
        insertRegion.top_level = 0
        insertRegion.d_type = 'Region';
        insertRegion.org_parent_id = currentRegion.id
        insertRegion.last_modified_version=1;

        if (subRegions.size() == 0) {
            //如果找不到下级 直接当前区划的innercode+0001
            insertRegion.inner_code = currentRegion.inner_code + "0001"
        } else {
            //如果找到下级,最大innercode+1
            subRegions.sort(new Comparator<Region>() {
                @Override
                int compare(Region o1, Region o2) {
                    return o1.inner_code.compareTo(o2.inner_code)
                }
            })
            Region maxRegion = subRegions.get(subRegions.size() - 1)
            insertRegion.inner_code = maxRegion.inner_code.substring(0, maxRegion.inner_code.length() - 1) + ((char)(maxRegion.inner_code.charAt(maxRegion.inner_code.length() - 1) + 1))
        }



        PreparedStatement ps2 = connection.prepareStatement("update org_region set leaf_node=?,code=? where id=?")
        ps2.setInt(1, 0)
        //非本级区划编码2-2-2，即截取level_num*2 位作为编码
        ps2.setString(2,currentRegion.code.substring(0,currentRegion.level_num*2))
        ps2.setLong(3, currentRegion.id)
        ps2.execute()
        ps2.close()


        insertObj(insertRegion, "org_region")
    }

    //对象转换为insert语句
    public static void insertObj(Object obj, String tableName) {
        String propStr = getClassFieldList(obj.getClass())
        int propSize = obj.metaClass.properties.size() - 1;
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < propSize; i++) {
            builder.append("?,")
        }
        String dotStr = builder.deleteCharAt(builder.length() - 1).toString()
        String insertSql = "insert into $tableName($propStr) values($dotStr)"
        println("insert sql : $insertSql")
        PreparedStatement ps = connection.prepareStatement(insertSql)
        int idx = 0;
        obj.metaClass.properties.forEach({ prop ->
            if (!prop.name.equalsIgnoreCase("class")) {
                if (prop.type == long.class) {
                    ps.setLong(idx + 1, obj."$prop.name")
                } else if (prop.type == String.class) {
                    ps.setString(idx + 1, obj."$prop.name")
                } else if (prop.type == int.class) {
                    ps.setInt(idx + 1, obj."$prop.name")
                } else {
                    throw new RuntimeException("不支持的类型$prop.type.name")
                }
                idx++;
            }
        })
        ps.execute()
        ps.close()
    }

    //查询转换为对象集合
    public static <T> List<T> getObjList(ResultSet rs, Class<T> t) {
        List<T> objList = []
        while (rs.next()) {
            T objTmp = t.newInstance();
            t.metaClass.properties.forEach({ prop ->
                if (!prop.name.equalsIgnoreCase("class")) {
                    if (prop.type == long.class) {
                        objTmp."$prop.name" = rs.getLong(prop.name)
                    } else if (prop.type == String.class) {
                        objTmp."$prop.name" = rs.getString(prop.name)

                    } else if (prop.type == int.class) {
                        objTmp."$prop.name" = rs.getInt(prop.name)
                    } else {
                        throw new RuntimeException("不支持的类型$prop.type.name")
                    }
                }
            })
            objList.add(objTmp)
        }
        return objList;
    }

    //获取一个类的所有字段，转换为 属性1,属性2,...
    public static String getClassFieldList(Class clazz) {
        StringBuilder builder = new StringBuilder();
        List<MetaProperty> fields = clazz.metaClass.properties
        fields.each {
            if (!it.name.equalsIgnoreCase("class")) {
                builder.append("${it.name},")
            }

        }
        return builder.deleteCharAt(builder.length() - 1).toString()
    }

    public Region getRegionInstance() {
        return new Region();
    }

    class Region {
        long id;
        String code;
        String name;
        String inner_code;
        int enabled;
        int leaf_node;
        int level_num;
        int year;
        long parent_id;
        int is_top_level;
        int top_level;
        String d_type = 'Region';
        long org_parent_id;
        int last_modified_version=0;


        @Override
        public String toString() {
            return "Region{" +
                    "id=" + id +
                    ", code='" + code + '\'' +
                    ", name='" + name + '\'' +
                    ", inner_code='" + inner_code + '\'' +
                    ", enabled=" + enabled +
                    ", leaf_node=" + leaf_node +
                    ", level_num=" + level_num +
                    ", year=" + year +
                    ", parent_id=" + parent_id +
                    ", is_top_level=" + is_top_level +
                    ", top_level=" + top_level +
                    ", d_type='" + d_type + '\'' +
                    ", org_parent_id=" + org_parent_id +
                    ", last_modified_version=" + last_modified_version +
                    '}';
        }
    }

    static class GenId {
        static AtomicInteger seq = new AtomicInteger(0);
        static long workId = (long) (new Random(System.nanoTime())).nextInt(2048);

        static long generate() {
            return System.currentTimeMillis() << 21 | workId << 10 | (long) seq.getAndUpdate({ operand ->
                ++operand;
                return operand % 1024;
            });
        }
    }
}
